/// <reference path="../Scripts/typings/jquery/jquery.d.ts" />
/// <reference path="../Scripts/typings/requirejs/require.d.ts" />
/// <reference path="../Scripts/typings/knockout/knockout.d.ts" />
/// <reference path="../Scripts/typings/knockout.mapping/knockout.mapping.d.ts" />
/// <reference path="../Scripts/typings/durandal/durandal.d.ts" />

interface KnockoutStatic {
    protectedObservable: KnockoutProtectedObservableStatic;
}

interface KnockoutProtectedObservableStatic extends KnockoutObservableStatic {
    <T>(value?: T): KnockoutProtectedObservable<T>;
}

interface KnockoutProtectedObservable<T> extends KnockoutObservable<T> {
    commit(): void;
    reset(): void;
    tempValue(): string;
}

class Main {

    public static bootstrapper(app, viewLocator, system, router, ko, mapping, jquery, jqueryui) {
        // Enable debug message to show in the console 
        system.debug(true);

        ko.mapping = mapping;

        ko.bindingHandlers.draggable = {
            init: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
                jQuery(element)
                    .data('bindingContext', bindingContext)
                    .draggable(bindingContext.$root.draggable);
                return ko.bindingHandlers.with.init.apply(this, arguments);
            }
        };
        ko.bindingHandlers.droppable = {
            init: (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) => {
                jQuery(element)
                    .data('bindingContext', bindingContext)
                    .droppable(bindingContext.$root.droppable);
                return ko.bindingHandlers.with.init.apply(this, arguments);
            }
        };

        // wrapper to an observable that requires accept/cancel
        // http://www.knockmeout.net/2011/03/guard-your-model-accept-or-cancel-edits.html
        ko.protectedObservable = (initialValue: any) => {
            var _actualValue = ko.observable(initialValue),
                _tempValue = initialValue;

            var result = ko.computed({
                read: () => {
                    return _actualValue();
                },
                write: (newValue) => {
                    _tempValue = newValue;
                }
            }).extend({ notify: "always" });

            result.commit = () => {
                if (_tempValue !== _actualValue()) {
                    _actualValue(_tempValue);
                }
            };

            result.reset = () => {
                _actualValue.valueHasMutated();
                _tempValue = _actualValue();   //reset temp value
            };

            result.tempValue = () => {
                return _tempValue;
            };

            return result;
        };

        app.title = 'd!scoArguments';

        app.configurePlugins({
            dialog: true,
            router: true
        });

        app.start().then(function () {
            viewLocator.useConvention();

            //Show the app by setting the root view model for our application.
            app.setRoot('viewmodels/shell'/*, 'entrance'*/);
        });
    }
}

// Maps the files so Durandal knows where to find these.
require.config({
    paths: {
        text: '../Scripts/text',
        durandal: '../Scripts/durandal',
        plugins: '../Scripts/durandal/plugins',
        transitions: '../Scripts/durandal/transitions',
        knockout: '../Scripts/knockout-3.1.0',
        komapping: '../Scripts/knockout.mapping-latest',
        jquery: '../Scripts/jquery-2.1.1',
        jqueryui: '../Scripts/jquery-ui-1.10.4',
        lib: '../app/lib',
        viewmodels: '../app/viewmodels',
        entities: '../app/viewmodels/entities',
        disco: '../Scripts/disco/disco'
    },
});

define(['durandal/app', 'durandal/viewLocator', 'durandal/system', 'plugins/router', 'knockout', 'komapping', 'jquery', 'jqueryui'], Main.bootstrapper);